#pragma once

#include "Object/Object.h"
#include "Containers/ScriptDelegateImplement.h"
#include "EditorSplitableLayoutModel.m.h"


//布局树节点
//布局树描述了分割布局控件的布局结构
RCLASS()
class REditorSplitableLayoutNode : public RObject
{
    ROBJECT

    //父节点
    TWeakObjectPtr<REditorSplitableLayoutNode> Parent;


    //在节点显隐改变后调用
    virtual void PostNodeVisibleChanged(bool NewVisible) {}

};


//描述一个节点的大小
RSTRUCT()
struct SEditorSplitableLayoutNodeSize
{
    ROBJECT

    //当前子控件的大小,单位为像素
    //如果总和不等于父控件的大小，会自动调整
    //永远>=MinSize
    RFIELD()
    float Size=1;

    //最小值，单位为像素
    RFIELD()
    float MinSize=0;

    //快速最小尺寸，单位为像素
    //这个尺寸永远>=最小值
    //快速最小化功能会用到这个值：
    //拖拽时如果计算得到的节点尺寸<=该尺寸，则将直接将节点大小设置为最小值
    //如果不想使用快速最小化功能，则将该值设置为最小值即可
    RFIELD()
    float QuickMinSize=0;
};


//水平/垂直布局节点，同时也是分割布局的非叶子节点
//至少含有两个子节点
RCLASS()
class REditorContainerSplitableLayoutNode : public REditorSplitableLayoutNode
{
    ROBJECT
public:
    RFIELD()
    TVector<REditorSplitableLayoutNodePtr> Children;


    void AddChild(
        REditorSplitableLayoutNodePtr InChild,
        float InSize,
        float InMinSize,
        float InQuickMinSize)
    {
        Children.Add(InChild);
        InChild->Parent=this;
        auto& Size = ChildrenSize.Emplace();
        Size.Size=InSize;
        Size.MinSize=InMinSize;
        Size.QuickMinSize=InQuickMinSize;
    }

    void InsertNode(int64_t InIndex,
        REditorSplitableLayoutNodePtr InChild,
        float InSize,
        float InMinSize,
        float InQuickMinSize)
    {
        Children.Insert(InIndex,InChild);
        InChild->Parent=this;
        SEditorSplitableLayoutNodeSize Size;
        Size.Size=InSize;
        Size.MinSize=InMinSize;
        Size.QuickMinSize=InQuickMinSize;
        ChildrenSize.Insert(InIndex,Size);
    }

    void RemoveChild(REditorSplitableLayoutNodePtr InChild)
    {
        auto Index = Children.Find(InChild).GetValue();
        InChild->Parent=nullptr;
        Children.RemoveAt(Index);
        ChildrenSize.RemoveAt(Index);
    }
    
    int64_t GetChildNum()
    {
        return Children.Num();
    }

    //是否是水平布局
    bool IsHorizontal() const { return bHorizontal; }
    void SetHorizontal() { bHorizontal = true; }

    //是否是垂直布局
    bool IsVertical() const { return !bHorizontal; }
    void SetVertical() { bHorizontal = false; }

    void SetSubNodeSize(int64_t SubNodeIndex,float NewSize )
    {
        if(ChildrenSize[SubNodeIndex].Size==NewSize)
        {
            return;
        }

        enum class EVisibleChange
        {
            NotChanged, //显隐没发生变化
            ToVisible , //从隐藏到显示
            ToInvisible,//从显示到隐藏
        };

        EVisibleChange VisibleChangeType=EVisibleChange::NotChanged;
        if(NewSize==0)
        {
            VisibleChangeType=EVisibleChange::ToInvisible;
        }
        else if(ChildrenSize[SubNodeIndex].Size==0)
        {
            VisibleChangeType=EVisibleChange::ToVisible;
        }

        ChildrenSize[SubNodeIndex].Size=NewSize;

        if(VisibleChangeType!=EVisibleChange::NotChanged)
        {
            Children[SubNodeIndex]->PostNodeVisibleChanged(VisibleChangeType==EVisibleChange::ToVisible);
        }
    }

    float GetSubNodeSize(int64_t InSubNodeIndex)
    {
        return ChildrenSize[InSubNodeIndex].Size;
    }

    float GetSubNodeMinSize(int64_t InSubNodeIndex)
    {
        return ChildrenSize[InSubNodeIndex].MinSize;
    }

    float GetSubNodeQuickMinSize(int64_t InSubNodeIndex)
    {
        return ChildrenSize[InSubNodeIndex].QuickMinSize;
    }

    float SizeSum()
    {
        float Sum=0;
        for(auto& Size: ChildrenSize)
        {
            Sum+=Size.Size;
        }
        return Sum;
    }
protected:
    //子控件的大小,单位为像素
    //如果总和不等于父控件的大小，会自动调整
    RFIELD()
    TVector<SEditorSplitableLayoutNodeSize> ChildrenSize;


    //在节点显隐改变后调用
    virtual void PostNodeVisibleChanged(bool NewVisible)  override
    {
        for(auto& Child:Children)
        {
            Child->PostNodeVisibleChanged(NewVisible);
        }
    }

protected:
    //如果为true,则是水平布局，否则是垂直布局
    RFIELD()
    bool bHorizontal = true;

    friend class REditorSplitableLayoutModel;
};

//分割布局的叶子节点
//用于放置分割后每个小控件的model
RCLASS()
class REditorSplitableLayoutLeafNode : public REditorSplitableLayoutNode
{
    ROBJECT
public:

    RFIELD()
    TSharedObjectPtr<RObject> ItemWidgetModel;

    //当大小变为0 以及从0改出时触发
    RFIELD()
    TScriptDelegate<void(bool /*NewVisible*/)> OnVisibleChanged;


protected:
    virtual void PostNodeVisibleChanged(bool NewVisible)  override
    {
        OnVisibleChanged.Broadcast(NewVisible);
    }

};

RCLASS()
class REditorSplitableLayoutModel : public RObject
{
    ROBJECT

public:

    void SetLayoutTree(REditorSplitableLayoutNodePtr InLayoutTree);
    REditorSplitableLayoutNodePtr GetLayoutRoot();
    void Clear();

    TDelegate<void> OnLayoutChanged;

    //所有的布局树节点，层序遍历，确保每个节点的父节点在前
    //在绘制时，从前往后绘制，比较容易实现
    RFIELD()
    TVector<REditorSplitableLayoutNodePtr> Nodes;

    //每个节点子节点的索引
    RFIELD()
    TVector<TVector<int64_t>> SubNodeIndices;


};
